﻿#region Copyright ©2008-2009, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: then $
// Last Changed Date     $LastChangedDate: 2009-06-09 09:28:29 +0200 (Tue, 09 Jun 2009) $
// Last Changed Revision $Rev: 185 $
//
// ====================================================================================================
#endregion

using System.IO;
using System.Xml;
using System.Collections.Generic;
using Tum.CollabXT.TFS.Resources;


namespace Tum.CollabXT.TFS
{
    class WSS : IProcessor
    {
        string SharePointDumpPath;
        const string SharePointServicesTemplateFolder = "Windows SharePoint Services";

        private List<string> WrittenLibraries = new List<string>();


        public WSS(string sharePointDumpPath)
        {
            this.SharePointDumpPath = sharePointDumpPath;
        }

        public void Process(IProcessProvider processProvider, TFSToolProvider toolProvider)
        {
            #region Check input values

            bool dumpPathGiven = true;
            if (SharePointDumpPath == null || SharePointDumpPath == "")
                dumpPathGiven = false;
            else
            {
                if (!Directory.Exists(SharePointDumpPath))
                    throw new TFSException(Language.Error_SharePointDirectoryNotFound);
                if (SharePointDumpPath.EndsWith("\\") || SharePointDumpPath.EndsWith("/"))
                    SharePointDumpPath = SharePointDumpPath.Substring(SharePointDumpPath.Length - 1);
            }
	        #endregion

            string wssTemplateFileName = toolProvider.OutputPath + "/" + SharePointServicesTemplateFolder + "/WssTasks.xml";
            #region Load template
            XmlDocument wssDoc = new XmlDocument();
            toolProvider.ProcessLog.AddEntry(Language.WSS_Loading);
            try
            {
                wssDoc.Load(wssTemplateFileName);
            }
            catch
            {
                toolProvider.ProcessLog.AddEntryAndThrowException(string.Format(Language.Error_LoadingFailed, wssTemplateFileName));
            }
            #endregion


            #region Write document libraries and folders
            //Select needed nodes from template
            toolProvider.ProcessLog.AddEntry(Language.WSS_SelectingLibrariesNode);
            var documentLibrariesNode = wssDoc.SelectSingleNode("/tasks/task[@id=\"SharePointPortal\"]/taskXml/Portal/documentLibraries");
            if (documentLibrariesNode == null)
                toolProvider.ProcessLog.AddEntryAndThrowException(Language.Error_NotFound_InvalidTemplate);



            toolProvider.ProcessLog.AddEntry(Language.WSS_SelectingFoldersNode);
            var foldersNode = wssDoc.SelectSingleNode("/tasks/task[@id=\"SharePointPortal\"]/taskXml/Portal/folders");
            if (foldersNode == null)
                toolProvider.ProcessLog.AddEntryAndThrowException(Language.Error_NotFound_InvalidTemplate);



            WriteChildFolders(toolProvider.OutputPath + "/" + SharePointServicesTemplateFolder + "/Process Guidance/", toolProvider.OutputPath.Length + SharePointServicesTemplateFolder.Length + 2, foldersNode, toolProvider.OutputPath);
            ///TODO: Remove hard-coding of this name
            WriteDocumentLibrary(documentLibrariesNode, "Process Guidance");

            if (dumpPathGiven)
            {
                foreach (string curFolder in Directory.GetDirectories(SharePointDumpPath))
                {
                    string libraryName = curFolder.Substring(SharePointDumpPath.Length + 1);

                    toolProvider.ProcessLog.AddEntry(string.Format(Language.WSS_WritingDocumentLibrary, libraryName));

                    WriteDocumentLibrary(documentLibrariesNode, libraryName);

                    //Create folder
                    Directory.CreateDirectory(toolProvider.OutputPath + "/" + SharePointServicesTemplateFolder + "/" + libraryName);

                    //Write child folders
                    WriteChildFolders(curFolder, SharePointDumpPath.Length + 1, foldersNode, toolProvider.OutputPath);
                }
            }
            #endregion


            #region Write files node
            toolProvider.ProcessLog.AddEntry(Language.WSS_SelectingFilesNode);
            var filesNode = wssDoc.SelectSingleNode("/tasks/task[@id=\"SharePointPortal\"]/taskXml/Portal/files");
            if (filesNode == null)
                toolProvider.ProcessLog.AddEntryAndThrowException(Language.Error_NotFound_InvalidTemplate);

            WriteFiles(toolProvider.OutputPath + "/" + SharePointServicesTemplateFolder + "/Process Guidance/", toolProvider.OutputPath.Length + SharePointServicesTemplateFolder.Length + 2, filesNode, toolProvider.OutputPath);

            if (dumpPathGiven)
            {
                foreach (string curFolder in Directory.GetDirectories(SharePointDumpPath))
                {
                    toolProvider.ProcessLog.AddEntry(string.Format(Language.WSS_CopyingFiles, curFolder.Substring(SharePointDumpPath.Length + 1)));
                    WriteFiles(curFolder, SharePointDumpPath.Length + 1, filesNode, toolProvider.OutputPath);
                }
            }
            #endregion


            #region Save WSS file
            toolProvider.ProcessLog.AddEntry(Language.WSS_Saving);
            try
            {
                wssDoc.Save(wssTemplateFileName);
            }
            catch
            {
                toolProvider.ProcessLog.AddEntryAndThrowException(string.Format(Language.Error_SavingFailed, wssTemplateFileName));
            }
            #endregion
        }

        private void WriteDocumentLibrary(XmlNode parentNode, string name)
        {
            if (!WrittenLibraries.Contains(name))
            {
                //Add document library node
                XmlNode docLibNode = parentNode.OwnerDocument.CreateNode("element", "documentLibrary", "");
                XmlAttribute nameAttribute = parentNode.OwnerDocument.CreateAttribute("name");
                nameAttribute.Value = name;
                docLibNode.Attributes.Append(nameAttribute);
                XmlAttribute descriptionAttribute = parentNode.OwnerDocument.CreateAttribute("description");
                descriptionAttribute.Value = name;
                docLibNode.Attributes.Append(descriptionAttribute);
                parentNode.AppendChild(docLibNode);

                WrittenLibraries.Add(name);
            }
        }

        /// <param name="libraryNameIndex">Position in the folder path, where the library name begins.</param>
        private void WriteChildFolders(string curFolder, int libraryNameIndex, XmlNode foldersNode, string outputPath)
        {
            string libraryName;
            int libraryNameEndPos = curFolder.IndexOfAny(Helper.FolderSeperators, libraryNameIndex);
            if(libraryNameEndPos < 0)
                libraryName = curFolder.Substring(libraryNameIndex);
            else
                libraryName = curFolder.Substring(libraryNameIndex, libraryNameEndPos - libraryNameIndex);

            foreach (string curChildFolder in Directory.GetDirectories(curFolder))
            {
                string childFolderName = curChildFolder.Substring(libraryNameIndex + libraryName.Length + 1).Replace('\\', '/');

                //Check if folder node already exists
                if (foldersNode.SelectNodes("folder[@name='" + childFolderName + "']").Count == 0)
                {
                    XmlNode newFolderNode = foldersNode.OwnerDocument.CreateNode("element", "folder", "");
                    XmlAttribute docLibraryAttribute = foldersNode.OwnerDocument.CreateAttribute("documentLibrary");
                    docLibraryAttribute.Value = libraryName;
                    newFolderNode.Attributes.Append(docLibraryAttribute);
                    XmlAttribute nameAttribute = foldersNode.OwnerDocument.CreateAttribute("name");
                    nameAttribute.Value = childFolderName;
                    newFolderNode.Attributes.Append(nameAttribute);
                    foldersNode.AppendChild(newFolderNode);
                }

                //Create folder
                Directory.CreateDirectory(outputPath + "/" + SharePointServicesTemplateFolder + "/" + libraryName + "/" + childFolderName);

                WriteChildFolders(curChildFolder, libraryNameIndex, foldersNode, outputPath);
            }
        }

        private void WriteFiles(string curFolder, int libraryNameIndex, XmlNode filesNode, string outputPath)
        {
            string libraryName;
            int libraryNameEndPos = curFolder.IndexOfAny(Helper.FolderSeperators, libraryNameIndex);
            if (libraryNameEndPos < 0)
            {
                libraryName = curFolder.Substring(libraryNameIndex);
                libraryNameEndPos = curFolder.Length;
            }
            else
                libraryName = curFolder.Substring(libraryNameIndex, libraryNameEndPos - libraryNameIndex);

            //Write files
            foreach (string curFilePath in Directory.GetFiles(curFolder))
            {
                string fileSource = SharePointServicesTemplateFolder + "/" + curFilePath.Substring(libraryNameIndex).Replace('\\', '/');

                //Check if file node already exists
                if (filesNode.SelectNodes("file[@source='" + fileSource + "']").Count == 0)
                {
                    XmlNode newFileNode = filesNode.OwnerDocument.CreateNode("element", "file", "");
                    XmlAttribute targetAttribute = filesNode.OwnerDocument.CreateAttribute("target");
                    targetAttribute.Value = curFilePath.Substring(libraryNameEndPos + 1).Replace('\\', '/');
                    newFileNode.Attributes.Append(targetAttribute);

                    XmlAttribute docLibraryAttribute = filesNode.OwnerDocument.CreateAttribute("documentLibrary");
                    docLibraryAttribute.Value = libraryName;
                    newFileNode.Attributes.Append(docLibraryAttribute);

                    XmlAttribute sourceAttribute = filesNode.OwnerDocument.CreateAttribute("source");
                    sourceAttribute.Value = fileSource;
                    newFileNode.Attributes.Append(sourceAttribute);
                    filesNode.AppendChild(newFileNode);
                }

                //Copy the file
                try
                {
                    string copyDest = outputPath + "/" + fileSource;
                    File.Copy(curFilePath, copyDest);
                    File.SetAttributes(copyDest, FileAttributes.Normal);
                }
                catch { }
            }

            //Write sub folder files
            foreach (string curSubFolder in Directory.GetDirectories(curFolder))
                WriteFiles(curSubFolder, libraryNameIndex, filesNode, outputPath);
        }
    }
}
